#include <linux/sched.h>
#include <asm/system.h>

void divide_error(void);
void debug(void);
void nmi(void);
void int3(void);
void overflow(void);
void bounds(void);
void invalid_op(void);
void coprocessor_segment_overrun(void);
void reserved(void);

static void die(char *str, long esp_ptr, long nr)
{
    long *esp = (long *) esp_ptr;
    int i;

    printk("%s: %04x\n\r",str, nr & 0xffff);
    printk("EIP:\t%04x:%p\n\rEFLAGS:\t%p\n\rESP:\t%04x:%p\n\r",
        esp[1], esp[0], esp[2], esp[4], esp[3]);
    cli();
    while (1);
}

void do_divide_error(long esp, long error_code)
{
    die("divide error", esp, error_code);
}

void do_int3(long *esp, long error_code,
        long fs, long es, long ds,
        long ebp, long esi, long edi,
        long edx, long ecx, long ebx, long eax)
{
    int tr;

    __asm__("str %%ax":"=a" (tr):"0" (0));    // 获取任务寄存器的值
    printk("eax\t\tebx\t\tecx\t\tedx\n\r%8x\t%8x\t%8x\t%8x\n\r",
        eax, ebx, ecx, edx);
    printk("esi\t\tedi\t\tebp\t\tesp\n\r%8x\t%8x\t%8x\t%8x\n\r",
        esi, edi, ebp, (long) esp);
    printk("\n\rds\tes\tfs\ttr\n\r%4x\t%4x\t%4x\t%4x\n\r",
        ds, es, fs, tr);
    printk("EIP: %8x   CS: %4x  EFLAGS: %8x\n\r",esp[0], esp[1], esp[2]);
}

void do_nmi(long esp, long error_code)
{
    die("nmi", esp, error_code);
}

void do_debug(long esp, long error_code)
{
    die("debug", esp, error_code);
}

void do_overflow(long esp, long error_code)
{
    die("overflow", esp, error_code);
}

void do_bounds(long esp, long error_code)
{
    die("bounds", esp, error_code);
}

void do_invalid_op(long esp, long error_code)
{
    die("invalid operand", esp, error_code);
}

void do_coprocessor_segment_overrun(long esp, long error_code)
{
    die("coprocessor segment overrun", esp, error_code);
}

void do_reserved(long esp, long error_code)
{
    die("reserved (15,17-47) error", esp, error_code);
}

void trap_init(void)
{
    int i;
    set_trap_gate(0, &divide_error);
    set_trap_gate(1, &debug);
    set_trap_gate(2, &nmi);
    set_system_gate(3, &int3);    /* int3-5 can be called from all */
    set_system_gate(4, &overflow);
    set_system_gate(5, &bounds);
    set_trap_gate(6, &invalid_op);
    set_trap_gate(9, &coprocessor_segment_overrun);
    set_trap_gate(15, &reserved);
    for (i = 17; i < 20; i++)
        set_trap_gate(i, &reserved);
}
